package v1

import (
	"strconv"
	"web_framework/config"
	"web_framework/model"
	. "web_framework/pkg/e"
	"web_framework/pkg/errno"
	"web_framework/router/api"
	"web_framework/service"
	"web_framework/storage"
	"web_framework/websocket/v1/handler"

	"github.com/gin-gonic/gin"

	"web_framework/router/middleware"

	"web_framework/pkg/constvar"
	)

type TaskAPI struct {
}

func (a TaskAPI) Name() string {
	return "task API"
}

func (a TaskAPI) Bind() {
	taskAPI := config.C.Router.Group("/api/v1/data", middleware.CheckVer(), middleware.TrackLog())
	{
		taskAPI.GET("resouce/add_video", addVideo)
		taskAPI.GET("resouce/del_video", delVideo)
		taskAPI.GET("resouce/pause_video", pauseVideo)
		taskAPI.GET("resouce/resume_video", resumeVideo)
		taskAPI.GET("task/done_list", doneList)
	}
}

type taskName struct {
	Name string `json:"name,omitempty"`
	Season  string  `json:"season,omitempty"`
	Episode string  `json:"episode,omitempty"`
}

var checkListAddVideo = []string{"sn", "token", "url", "name"}
//2.6	云端添加影片下载任务
func addVideo(c *gin.Context) {
	// 检查参数是否为空
	err, params := CheckEmptyParams(c, checkListAddVideo)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}
	var nameData taskName
	c.Bind(&nameData)
	//查询等待中的任务数
	waitTaskNum, getLenErr := service.GetWaitTaskNum(params["sn"])
	if getLenErr != nil {
		api.SendResponse(c, errno.ErrGetWaitTaskNum, nil)
		return
	}
	if waitTaskNum >= storage.RouterTaskWaitingMax {
		api.SendResponse(c, errno.ErrWaitTaskMax, nil)
		return
	}
	deviceInfo, errDev := storage.GetDeviceBySn(config.C.DB.DB, params["sn"])
	if errDev != nil {
		api.SendResponse(c, errDev, nil)
		return
	}
	//任务入库
	tx, txErr := config.C.DB.DB.Beginx()
	if txErr != nil {
		Log("Info", "事务启动失败")
	}
	task := model.Task{
		DeviceID: deviceInfo.DeviceID,
		URL:      params["url"],
		ResName:  params["name"],
	}
	result, createErr := storage.CreateTask(tx, task)
	if createErr != nil {
		if err := tx.Rollback(); err != nil {
			api.SendResponse(c, err, nil)
			return
		}
		api.SendResponse(c, createErr, nil)
		return
	}
	taskId, _ := result.LastInsertId()
	//缓存任务详情
	taskIdStr := strconv.FormatInt(taskId, 10)
	taskInfoCacheKey := constvar.RouterRedisPrefix + params["sn"] + storage.RedisRouterTaskInfoKey + ":" + taskIdStr
	//获取剧集信息
	var seasonStr string
	var episodeStr string
	if len(nameData.Season) != 0{
		seasonStr = GetZimuzuSeason(nameData.Season)
	}
	if len(nameData.Episode) != 0 {
		episodeStr = "第"+nameData.Episode+"集"
	}
	cacheData := map[string]interface{}{
		"taskId":         taskId,
		"speed":          0,
		"totalSize":      0,
		"downloadedSize": 0,
		"path":           "",
		"name":           params["name"] + " " + seasonStr + " " + episodeStr,
		"url":            params["url"],
		"status":         model.TaskStatusCreating,
	}
	_, setErr := storage.RedisHSet(taskInfoCacheKey, cacheData, -1)
	if setErr != nil {
		Log("Info", "任务信息缓存失败")
		if err := tx.Rollback(); err != nil {
			api.SendResponse(c, err, nil)
			return
		}
		api.SendResponse(c, errno.ErrTaskCache, nil)
		return
	}
	//添加任务至队列
	if err := service.AddTaskToLoadQueue(taskId, params["sn"]); err != nil {
		Log("Info", "添加下载任务进入队列失败")
		if err := tx.Rollback(); err != nil {
			api.SendResponse(c, err, nil)
			return
		}
		api.SendResponse(c, errno.ErrTaskToQueue, nil)
		return
	}
	//查询当前下载队列中的任务数
	loadingTaskQueueCacheKey := constvar.RouterRedisPrefix + params["sn"] + storage.RedisRouterTaskLoadIngSetKey
	laodTaskNum, loadingErr := storage.RedisZCard(loadingTaskQueueCacheKey)
	if loadingErr != nil {
		Log("Info", "获取队列任务数失败")
		if err := tx.Rollback(); err != nil {
			api.SendResponse(c, err, nil)
			return
		}
		api.SendResponse(c, errno.ErrTaskToQueue, nil)
		return
	}
	if laodTaskNum >= storage.RouterTaskLoadingMax {
		service.AddTaskToWaitQueue(taskId, params["sn"])
	} else {
		if err := service.AddTaskToLoadingQueue(taskId, params["sn"]); err != nil {
			api.SendResponse(c, errno.ErrAddTaskToLoadingTask, nil)
			return
		}
		//任务推送
		msg, msgErr := service.PushTaskQueueToRouterData(params["sn"])
		if msgErr != nil {
			api.SendResponse(c, errno.ErrDealLoadTask, nil)
			return
		}
		client := []string{params["sn"]}
		errSend := handler.WriteMessage(client, msg)
		if errSend != nil {
			api.SendResponse(c, errno.ErrDealLoadTask, nil)
			return
		}
		go func() {
			if err := service.CyclicCheckTaskStatus(params["sn"], taskId, model.TaskStatusLoadFail, model.TaskStatusloading); err != nil {
				//任务处理结果通知
				if err := taskNotice(params["sn"] , taskId , "添加失败");err != nil {
					Log("Info", "消息通知失败:", err.Error())
					return
				}
				//从下载队列中移除
				if err := service.DelTaskFromLoadingQueue(taskId, params["sn"]); err != nil {
					return
				}

				return
			}
			//任务处理结果通知
			if err := taskNotice(params["sn"] , taskId , "添加成功");err != nil {
				Log("Info", "消息通知失败:", err.Error())
				return
			}

			return
		}()
	}

	commitErr := tx.Commit()
	if commitErr != nil {
		Log("Info", "添加下载任务事务提交失败")
	}

	api.SendResponse(c, errno.OK, nil)
	return

}

var checkListDelVideo = []string{"sn", "uid", "token", "taskId"}

func delVideo(c *gin.Context) {
	// 检查参数是否为空
	err, params := CheckEmptyParams(c, checkListDelVideo)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}
	taskInfoCacheKey := constvar.RouterRedisPrefix + params["sn"] + storage.RedisRouterTaskInfoKey + ":" + params["taskId"]
	res, err := storage.RedisHGetAll(taskInfoCacheKey)
	if err != nil {
		Log("Info", "任务获取详情失败")
	}
	taskStatusInt, _ := strconv.Atoi(res["status"].(string))
	//if taskStatusInt == model.TaskStatusDeleting || taskStatusInt == model.TaskStatusCreating || taskStatusInt == model.TaskStatusPauseing {
	//	api.SendResponse(c, errno.ErrDelTaskRequest, nil)
	//	return
	//}
	//修改任务状态为删除中
	taskIdInt64, _ := strconv.ParseInt(res["taskId"].(string), 10, 64)
	service.UpdateQueueTaskStatus(taskIdInt64, params["sn"], model.TaskStatusDeleting)

	taskUrlStr := res["url"].(string)
	switch taskStatusInt {
	//删除下载中的任务
	case model.TaskStatusloading:
		//推送至下载模块
		if err := pushDelTaskToRouter(params["sn"], taskIdInt64, taskUrlStr); err != nil {
			api.SendResponse(c, errno.ErrDealLoadTask, nil)
			return
		}
		//协程查询任务状态
		go func() {
			if err := service.CyclicCheckTaskStatus(params["sn"], taskIdInt64, model.TaskStatusPaused, model.TaskStatusDeleted); err != nil {
				if err := service.DelTaskFromLoadingQueue(taskIdInt64, params["sn"]); err != nil {
					return
				}
				//任务处理结果通知
				if err := taskNotice(params["sn"] , taskIdInt64 , "删除失败");err != nil {
					Log("Info", "消息通知失败", err.Error())
					return
				}
				return
			}
			if err := service.DelTaskFromLoadQueue(taskIdInt64, params["sn"]); err != nil {
				Log("Info", err.Error())
				return
			}
			if err := service.DelTaskFromLoadingQueue(taskIdInt64, params["sn"]); err != nil {
				Log("Info", err.Error())
				return
			}
			//任务处理结果通知
			if err := taskNotice(params["sn"] , taskIdInt64 , "删除成功");err != nil {
				Log("Info", "消息通知失败:", err.Error())
				return
			}
		}()
	//删除等待中的任务
	case model.TaskStatusWaiting:
		if err := service.DelTaskFromLoadQueue(taskIdInt64, params["sn"]); err != nil {
			api.SendResponse(c, err, nil)
			return
		}
		if err := service.DelTaskFromWaitQueue(taskIdInt64, params["sn"]); err != nil {
			api.SendResponse(c, err, nil)
			return
		}
		service.UpdateQueueTaskStatus(taskIdInt64, params["sn"], model.TaskStatusDeleted)
		//任务处理结果通知
		if err := taskNotice(params["sn"] , taskIdInt64 , "删除成功");err != nil {
			Log("Info", "消息通知失败:", err.Error())
			return
		}

	//删除已暂停的任务
	case model.TaskStatusPaused:
		//推送至下载模块
		if err := pushDelTaskToRouter(params["sn"], taskIdInt64, taskUrlStr); err != nil {
			api.SendResponse(c, errno.ErrDealLoadTask, nil)
			return
		}
		//协程查询任务状态
		go func() {
			if err := service.CyclicCheckTaskStatus(params["sn"], taskIdInt64, model.TaskStatusPaused, model.TaskStatusDeleted); err != nil {
				//任务处理结果通知
				if err := taskNotice(params["sn"] , taskIdInt64 , "删除成功");err != nil {
					Log("Info", "消息通知失败:", err.Error())
					return
				}
				return
			}
			if err := service.DelTaskFromLoadQueue(taskIdInt64, params["sn"]); err != nil {
				Log("Info", err.Error())
				return
			}
			//任务处理结果通知
			if err := taskNotice(params["sn"] , taskIdInt64 , "删除成功");err != nil {
				Log("Info", "消息通知失败:", err.Error())
				return
			}
		}()
	//删除下载失败的任务
	case model.TaskStatusLoadFail:
		//删除未完成队列的任务
		if err := service.DelTaskFromLoadQueue(taskIdInt64, params["sn"]); err != nil {
			Log("Info", err.Error())
			return
		}
		service.UpdateQueueTaskStatus(taskIdInt64, params["sn"], model.TaskStatusDeleted)
		//任务处理结果通知
		if err := taskNotice(params["sn"] , taskIdInt64 , "删除成功");err != nil {
			Log("Info", "消息通知失败:", err.Error())
			return
		}
	default:
		//更新任务队列信息
		if err := service.DelLoadTask(taskIdInt64, params["sn"], model.TaskStatusDeleted); err != nil {
			Log("Info", err.Error())
			return
		}

		service.UpdateQueueTaskStatus(taskIdInt64, params["sn"], model.TaskStatusDeleted)
		//任务处理结果通知
		if err := taskNotice(params["sn"] , taskIdInt64 , "删除成功");err != nil {
			Log("Info", "消息通知失败:", err.Error())
			return
		}
	}

	api.SendResponse(c, errno.OK, nil)
	return
}

func resumeVideo(c *gin.Context) {
	// 检查参数是否为空
	err, params := CheckEmptyParams(c, checkListDelVideo)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}
	//查看等待中的队列
	waitTaskNum, getLenErr := service.GetWaitTaskNum(params["sn"])
	if getLenErr != nil {
		api.SendResponse(c, errno.ErrGetWaitTaskNum, nil)
		return
	}
	if waitTaskNum >= storage.RouterTaskWaitingMax {
		api.SendResponse(c, errno.ErrWaitTaskMax, nil)
		return
	}
	//查看当前任务信息
	taskInfoCacheKey := constvar.RouterRedisPrefix + params["sn"] + storage.RedisRouterTaskInfoKey + ":" + params["taskId"]
	res, err := storage.RedisHGetAll(taskInfoCacheKey)
	if err != nil {
		Log("Info", "任务获取详情失败:", err.Error())
	}
	taskStatusInt, _ := strconv.Atoi(res["status"].(string))
	if taskStatusInt != model.TaskStatusPaused {
		api.SendResponse(c, errno.ErrResumeTaskRequest, nil)
		return
	}
	taskIdInt64, _ := strconv.ParseInt(res["taskId"].(string), 10, 64)

	//判断当前任务状态是否允许此操作
	if taskStatusInt == model.TaskStatusDeleting || taskStatusInt == model.TaskStatusCreating || taskStatusInt == model.TaskStatusPauseing {
		api.SendResponse(c, errno.ErrDelTaskRequest, nil)
		return
	}
	//查询当前下载队列中的任务数
	loadingTaskQueueCacheKey := constvar.RouterRedisPrefix + params["sn"] + storage.RedisRouterTaskLoadIngSetKey
	laodTaskNum, loadingErr := storage.RedisZCard(loadingTaskQueueCacheKey)
	if loadingErr != nil {
		Log("Info", "获取队列任务数失败:", loadingErr.Error())
		api.SendResponse(c, errno.ErrTaskToQueue, nil)
		return
	}
	if laodTaskNum >= storage.RouterTaskLoadingMax {
		service.AddTaskToWaitQueue(taskIdInt64, params["sn"])
	} else {
		if err := service.AddTaskToLoadingQueue(taskIdInt64, params["sn"]); err != nil {
			api.SendResponse(c, errno.ErrAddTaskToLoadingTask, nil)
			return
		}

		//修改任务状态为创建中
		taskIdInt64, _ := strconv.ParseInt(res["taskId"].(string), 10, 64)
		service.UpdateQueueTaskStatus(taskIdInt64, params["sn"], model.TaskStatusCreating)

		//任务推送
		msg, msgErr := service.PushTaskQueueToRouterData(params["sn"])
		if msgErr != nil {
			api.SendResponse(c, errno.ErrDealLoadTask, nil)
			return
		}
		client := []string{params["sn"]}
		errSend := handler.WriteMessage(client, msg)
		if errSend != nil {
			api.SendResponse(c, errno.ErrDealLoadTask, nil)
			return
		}

		//协程查询任务状态
		go func() {
			if err := service.CyclicCheckTaskStatus(params["sn"], taskIdInt64, model.TaskStatusPaused, model.TaskStatusloading); err != nil {
				//从下载队列中移除
				if err := service.DelTaskFromLoadingQueue(taskIdInt64, params["sn"]); err != nil {
					Log("Info", err.Error())
				}
				//任务处理结果通知
				if err := taskNotice(params["sn"] , taskIdInt64 , "启动失败");err != nil {
					Log("Info", "消息通知失败:", err.Error())
					return
				}
			}
			//任务处理结果通知
			if err := taskNotice(params["sn"] , taskIdInt64 , "启动成功");err != nil {
				Log("Info", "消息通知失败:", err.Error())
				return
			}
		}()
	}

	api.SendResponse(c, errno.OK, nil)
	return

}

func pauseVideo(c *gin.Context) {
	// 检查参数是否为空
	err, params := CheckEmptyParams(c, checkListDelVideo)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}
	taskInfoCacheKey := constvar.RouterRedisPrefix + params["sn"] + storage.RedisRouterTaskInfoKey + ":" + params["taskId"]
	res, err := storage.RedisHGetAll(taskInfoCacheKey)
	if err != nil {
		Log("Info", "任务获取详情失败:", err.Error())
	}
	taskStatusInt, _ := strconv.Atoi(res["status"].(string))
	if taskStatusInt != model.TaskStatusloading {
		api.SendResponse(c, errno.ErrPauseTaskRequest, nil)
		return
	}
	//判断当前任务状态是否允许此操作
	if taskStatusInt == model.TaskStatusDeleting || taskStatusInt == model.TaskStatusCreating || taskStatusInt == model.TaskStatusPauseing {
		api.SendResponse(c, errno.ErrDelTaskRequest, nil)
		return
	}

	//修改任务状态为暂停中
	taskIdInt64, _ := strconv.ParseInt(res["taskId"].(string), 10, 64)
	service.UpdateQueueTaskStatus(taskIdInt64, params["sn"], model.TaskStatusPauseing)

	//任务推送
	msg, msgErr := service.PushTaskQueueToRouterData(params["sn"])
	if msgErr != nil {
		api.SendResponse(c, errno.ErrDealLoadTask, nil)
		return
	}
	client := []string{params["sn"]}
	errSend := handler.WriteMessage(client, msg)
	if errSend != nil {
		api.SendResponse(c, errno.ErrDealLoadTask, nil)
		return
	}
	//协程查询任务状态
	go func() {
		if err := service.CyclicCheckTaskStatus(params["sn"], taskIdInt64, model.TaskStatusloading, model.TaskStatusPaused); err != nil {
			//任务处理结果通知
			if err = taskNotice(params["sn"] , taskIdInt64 , "暂停失败");err != nil {
				Log("Info", "消息通知失败:", err.Error())
				return
			}
			return
		}
		//从下载队列中移除
		if err := service.DelTaskFromLoadingQueue(taskIdInt64, params["sn"]); err != nil {
			Log("Info", err.Error())
			return
		}
		//任务处理结果通知
		if err := taskNotice(params["sn"] , taskIdInt64 , "暂停成功");err != nil {
			Log("Info", "消息通知失败:", err.Error())
			return
		}
	}()

	api.SendResponse(c, errno.OK, nil)
	return
}

func pushDelTaskToRouter(sn string, taskId int64, taskUrl string) error {
	msg, msgErr := service.DelTaskToRouterData(sn, taskId, taskUrl)
	if msgErr != nil {
		return msgErr
	}
	client := []string{sn}
	errSend := handler.WriteMessage(client, msg)
	if errSend != nil {
		return errSend
	}

	return nil
}

var checkListDoneList = []string{"sn", "uid", "token", "pageNo"}
//分页查询已完成的任务列表
func doneList(c *gin.Context) {
	// 检查参数是否为空
	err, params := CheckEmptyParams(c, checkListDoneList)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}
	deviceInfo, getDeviceErr := storage.GetDeviceBySn(config.C.DB.DB, params["sn"])
	if getDeviceErr != nil {
		api.SendResponse(c, getDeviceErr, nil)
		return
	}
	pageNoInt, _ := strconv.Atoi(params["pageNo"])
	tasks, getTaskErr := storage.GetTask(config.C.DB.DB, deviceInfo.DeviceID, model.TaskStatusComplete, pageNoInt)
	if getTaskErr != nil {
		api.SendResponse(c, getTaskErr, nil)
		return
	}
	type TaskData struct {
		TaskID       int64  `json:"taskId"`
		Name         string `json:"name"`
		Path         string `json:"path"`
		URL          string `json:"url"`
		TotalSize    int    `json:"totalSize"`
		DownloadSize int    `json:"downloadSize"`
		Time         int64  `json:"time"`
		Status       int    `json:"status"`
	}

	var returnData = make([]TaskData,0)

	for _, task := range tasks {
		newTask := TaskData{
			TaskID:       task.TaskID,
			Name:         task.ResName,
			Path:         task.Path,
			URL:          task.URL,
			TotalSize:    task.TotalSize,
			DownloadSize: task.DownloadSize,
			Time:         task.CompleteTime.Unix(),
			Status:       10,
		}
		returnData = append(returnData, newTask)
	}
	errno.OK.Info = "获取列表成功"
	api.SendResponse(c, errno.OK, returnData)
	return

}

//任务通知
func taskNotice(sn string, taskId int64 , notice string) error {
	//查询绑定路由器的uid
	deviceBindInfo, err := storage.GetDeviceBindBySn(config.C.DB.DB, sn)
	if err != nil {
		return err
	}
	//获取推送的消息体
	msg, msgErr := service.TaskDealResultNoticeData(sn, taskId, notice)
	if msgErr != nil {
		return msgErr
	}
	//查询uid下的所有有效token
	tokenKey := constvar.RedisUserToken + strconv.FormatInt(deviceBindInfo.UID.Int64, 10)
	tokenSilce, _ := storage.RedisZRange(tokenKey, 0, 10)
	//推送
	errSend := handler.WriteMessage(tokenSilce, msg)
	if errSend != nil {
		return errSend
	}

	return nil
}
